Skip to content

Conversation

@Allda
Copy link
Collaborator

@Allda Allda commented Jan 14, 2026

What does this PR do?

Add init container for workspace restoration

A new init container is added to the workspace deployment in case user choose to restore the workspace from backup.

By setting the workspace attribute "controller.devfile.io/restore-workspace" the controller sets a new init container instead of cloning data from git repository.

By default an automated path to restore image is used based on cluster settings. However user is capable overwrite that value using another attribute "controller.devfile.io/restore-source-image".

The restore container runs a wokspace-recovery.sh script that pull an image using oras an extract files to a /project directory.

What issues does this PR fix or reference?

#1525

Is it tested? How?

No automated tests are available in the first phase. I will add tests once I get the first approval that the concept is ok.

How to test:

  • Configure a cluster to enable backups
  • Create a new workspace and make changes in any of its files and save it.
  • Stop the workspace `kubectl patch devworkspace restore-workspace-2 --type=merge -p '{"spec": {"started": false}}'
  • Wait till it is stopped, and backup is executed for the workspace (verify the backup image exists in the registry)
  • Delete a workspace from cluster kubectl delete devworkspace restore-workspace-2
  • Add an attribute to the workspace CRD as shown below (controller.devfile.io/restore-workspace)
  • Create a workspace
  • Wait till it boots up and verify the changed file is present
kind: DevWorkspace
apiVersion: workspace.devfile.io/v1alpha2
metadata:
  labels:
    controller.devfile.io/creator: ""
  name: restore-workspace-2
spec:
  started: true
  routingClass: 'basic'
  template:
    attributes:
      controller.devfile.io/storage-type: common
      controller.devfile.io/restore-workspace: 'true'

PR Checklist

  • E2E tests pass (when PR is ready, comment /test v8-devworkspace-operator-e2e, v8-che-happy-path to trigger)
    • v8-devworkspace-operator-e2e: DevWorkspace e2e test
    • v8-che-happy-path: Happy path for verification integration with Che

What's missing:

  • integration with registry authentication ✅
  • integration with built-in OCP registry ✅

@openshift-ci
Copy link

openshift-ci bot commented Jan 14, 2026

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: Allda
Once this PR has been reviewed and has the lgtm label, please assign dkwon17 for approval. For more information see the Code Review Process.

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

Allda added 4 commits January 16, 2026 09:56
A new init container is added to the workspace deployment in case user
choose to restore the workspace from backup.

By setting workspace attribute "controller.devfile.io/restore-workspace"
the controller sets a new init container instead of cloning data from
git repository.

By default an automated path to restore image is used based on cluster
settings. However user is capable overwrite that value using another
attribute "controller.devfile.io/restore-source-image".

The restore container runs a wokspace-recovery.sh script that pull an
image using oras an extract files to a /project directory.

Signed-off-by: Ales Raszka <araszka@redhat.com>
A new tests that verifies the workspace is created from a backup. It
checks if a deployment is ready and if it contains a new restore init
container with proper configuration.

There are 2 tests - one focused on common pvc and other that have
per-workspace storage.

Signed-off-by: Ales Raszka <araszka@redhat.com>
The condition whether an workspace should be restored from workspace was
in the restore module itself. This make a reading a code more difficult.
Now the condition is checked in the controller itself and restore
container is only added when enabled.

This commit also fixes few minor changes based on the code review
comments:
- Licence header
- Attribute validation
- Add a test for disabled workspace recovery
- Typos

Signed-off-by: Ales Raszka <araszka@redhat.com>
A new config is added to control the restore container. Default values
are set for the new init container. It can be changed by user in the
config. The config uses same logic as the project clone container
config.

Signed-off-by: Ales Raszka <araszka@redhat.com>
@rohanKanojia
Copy link
Member

@Allda : I'm facing a strange issue while testing this functionality on CRC cluster . I've tried on both amd64 and arm64 variants but face same issue. I used samples/plain-workspace.yaml for testing.

Everything goes fine till step 4, but when I create the restore backup manifest I can see devworkspace resource is created but there is no corresponding pod for it:

oc create -f restore-dw.yaml
devworkspace.workspace.devfile.io/plain-devworkspace created
oc get dw
NAME                 DEVWORKSPACE ID             PHASE     INFO
plain-devworkspace   workspace612b8ddca9ff45d5   Running   Workspace is running
oc get pods
No resources found in rokumar-dev namespace.

I had just modified the name from the restore manifest you shared:

kind: DevWorkspace
apiVersion: workspace.devfile.io/v1alpha2
metadata:
  labels:
    controller.devfile.io/creator: ""
  name: plain-devworkspace
spec:
  started: true
  routingClass: 'basic'
  template:
    attributes:
      controller.devfile.io/storage-type: common
      controller.devfile.io/restore-workspace: 'true'

Could you please check if I'm missing something?

@Allda
Copy link
Collaborator Author

Allda commented Jan 21, 2026

@Allda : I'm facing a strange issue while testing this functionality on CRC cluster . I've tried on both amd64 and arm64 variants but face same issue. I used samples/plain-workspace.yaml for testing.

Everything goes fine till step 4, but when I create the restore backup manifest I can see devworkspace resource is created but there is no corresponding pod for it:

oc create -f restore-dw.yaml
devworkspace.workspace.devfile.io/plain-devworkspace created
oc get dw
NAME                 DEVWORKSPACE ID             PHASE     INFO
plain-devworkspace   workspace612b8ddca9ff45d5   Running   Workspace is running
oc get pods
No resources found in rokumar-dev namespace.

I had just modified the name from the restore manifest you shared:

kind: DevWorkspace
apiVersion: workspace.devfile.io/v1alpha2
metadata:
  labels:
    controller.devfile.io/creator: ""
  name: plain-devworkspace
spec:
  started: true
  routingClass: 'basic'
  template:
    attributes:
      controller.devfile.io/storage-type: common
      controller.devfile.io/restore-workspace: 'true'

Could you please check if I'm missing something?

I am not sure why it doesn't work on your system. I tried the workspace you mentioned and the backup and other pods were created successfully.

~ k get deployments -n araszka
NAME                        READY   UP-TO-DATE   AVAILABLE   AGE
workspacefba99cfc93514828   1/1     1            1           40s

~ k get pods -n araszka                                                               
NAME                                         READY   STATUS             RESTARTS      AGE
fuse-builder-pod                             0/1     ImagePullBackOff   2 (20d ago)   63d
workspacefba99cfc93514828-84b865df77-t5gwz   1/1     Running            0             51s

Are there any logs you can share or see if the workspace has any pods at the very start?

@dkwon17
Copy link
Collaborator

dkwon17 commented Jan 23, 2026

@Allda thank you for the updates,

a private registry (quay.io) with auth

I ran into some issues with this in my lab cluster where the auth secret isn't mounting properly onto the restore initcontainer, I will investigate more on Monday and provide more feedback

@rohanKanojia
Copy link
Member

rohanKanojia commented Jan 27, 2026

I tested, and I was able to restore workspace from backup using OpenShift Internal registry and Quay.io.

Logs of restored workspace workspace-restore container with OpenShift Internal registry:

------------------------------------------
📌 Pod: workspacee119c8fcfc124631-57b8699795-k2jl4
🔹 Logs for container: workspace-restore

Restoring devworkspace from image 'default-route-openshift-image-registry.apps-crc.testing/openshift-operators/test-devworkspace-should-get-backup:latest' to path '/projects'
Using mounted service account token for registry authentication
Login Succeeded
Downloading fde49750175c devworkspace-backup.tar.gz
Downloaded  fde49750175c devworkspace-backup.tar.gz
Pulled [registry] default-route-openshift-image-registry.apps-crc.testing/openshift-operators/test-devworkspace-should-get-backup:latest
Digest: sha256:f0060e5ca2e3183846cddbadc451c0d2183044aabc98016e468fdb42c4f0a464
./
./web-nodejs-sample/
./web-nodejs-sample/.gitattributes
./web-nodejs-sample/.gitignore
./web-nodejs-sample/LICENSE
./web-nodejs-sample/README.md
./web-nodejs-sample/devfile.yaml
./web-nodejs-sample/package-lock.json
./web-nodejs-sample/package.json
./web-nodejs-sample/.git/
./web-nodejs-sample/.git/description
./web-nodejs-sample/.git/config
./web-nodejs-sample/.git/HEAD
./web-nodejs-sample/.git/packed-refs
./web-nodejs-sample/.git/index
./web-nodejs-sample/.git/FETCH_HEAD
./web-nodejs-sample/.git/branches/
./web-nodejs-sample/.git/hooks/
./web-nodejs-sample/.git/hooks/applypatch-msg.sample
./web-nodejs-sample/.git/hooks/commit-msg.sample
./web-nodejs-sample/.git/hooks/fsmonitor-watchman.sample
./web-nodejs-sample/.git/hooks/post-update.sample
./web-nodejs-sample/.git/hooks/pre-applypatch.sample
./web-nodejs-sample/.git/hooks/pre-commit.sample
./web-nodejs-sample/.git/hooks/pre-merge-commit.sample
./web-nodejs-sample/.git/hooks/pre-push.sample
./web-nodejs-sample/.git/hooks/pre-rebase.sample
./web-nodejs-sample/.git/hooks/pre-receive.sample
./web-nodejs-sample/.git/hooks/prepare-commit-msg.sample
./web-nodejs-sample/.git/hooks/push-to-checkout.sample
./web-nodejs-sample/.git/hooks/sendemail-validate.sample
./web-nodejs-sample/.git/hooks/update.sample
./web-nodejs-sample/.git/info/
./web-nodejs-sample/.git/info/exclude
./web-nodejs-sample/.git/objects/
./web-nodejs-sample/.git/objects/pack/
./web-nodejs-sample/.git/objects/pack/pack-00c9cb529f78a543deaf778dfaffcb012aef3c11.pack
./web-nodejs-sample/.git/objects/pack/pack-00c9cb529f78a543deaf778dfaffcb012aef3c11.rev
./web-nodejs-sample/.git/objects/pack/pack-00c9cb529f78a543deaf778dfaffcb012aef3c11.idx
./web-nodejs-sample/.git/objects/info/
./web-nodejs-sample/.git/refs/
./web-nodejs-sample/.git/refs/heads/
./web-nodejs-sample/.git/refs/heads/main
./web-nodejs-sample/.git/refs/tags/
./web-nodejs-sample/.git/refs/remotes/
./web-nodejs-sample/.git/refs/remotes/origin/
./web-nodejs-sample/.git/refs/remotes/origin/HEAD
./web-nodejs-sample/.git/logs/
./web-nodejs-sample/.git/logs/HEAD
./web-nodejs-sample/.git/logs/refs/
./web-nodejs-sample/.git/logs/refs/remotes/
./web-nodejs-sample/.git/logs/refs/remotes/origin/
./web-nodejs-sample/.git/logs/refs/remotes/origin/HEAD
./web-nodejs-sample/.git/logs/refs/heads/
./web-nodejs-sample/.git/logs/refs/heads/main
./web-nodejs-sample/.github/
./web-nodejs-sample/.github/CODEOWNERS
./web-nodejs-sample/.vscode/
./web-nodejs-sample/.vscode/launch.json
./web-nodejs-sample/app/
./web-nodejs-sample/app/app.js
./.code-workspace
Restore completed successfully.

Logs of restored workspace from Quay.io:

Restoring devworkspace from image 'quay.io/rokumar/openshift-operators/test-devworkspace-should-get-backup:latest' to path '/projects'
Using mounted service account token for registry authentication
Downloading 81626b3c4946 devworkspace-backup.tar.gz
Downloaded  81626b3c4946 devworkspace-backup.tar.gz
Pulled [registry] quay.io/rokumar/openshift-operators/test-devworkspace-should-get-backup:latest
Digest: sha256:9799ddfd7a08ccfdc5673e952849982a4df2d3746f3f6d7b9a996f49b4ccdd2e
./
./web-nodejs-sample/
./web-nodejs-sample/.git/
./web-nodejs-sample/.git/branches/
./web-nodejs-sample/.git/description
./web-nodejs-sample/.git/hooks/
./web-nodejs-sample/.git/hooks/applypatch-msg.sample
./web-nodejs-sample/.git/hooks/commit-msg.sample
./web-nodejs-sample/.git/hooks/fsmonitor-watchman.sample
./web-nodejs-sample/.git/hooks/post-update.sample
./web-nodejs-sample/.git/hooks/pre-applypatch.sample
./web-nodejs-sample/.git/hooks/pre-commit.sample
./web-nodejs-sample/.git/hooks/pre-merge-commit.sample
./web-nodejs-sample/.git/hooks/pre-push.sample
./web-nodejs-sample/.git/hooks/pre-rebase.sample
./web-nodejs-sample/.git/hooks/pre-receive.sample
./web-nodejs-sample/.git/hooks/prepare-commit-msg.sample
./web-nodejs-sample/.git/hooks/push-to-checkout.sample
./web-nodejs-sample/.git/hooks/sendemail-validate.sample
./web-nodejs-sample/.git/hooks/update.sample
./web-nodejs-sample/.git/info/
./web-nodejs-sample/.git/info/exclude
./web-nodejs-sample/.git/config
./web-nodejs-sample/.git/objects/
./web-nodejs-sample/.git/objects/pack/
./web-nodejs-sample/.git/objects/pack/pack-00c9cb529f78a543deaf778dfaffcb012aef3c11.pack
./web-nodejs-sample/.git/objects/pack/pack-00c9cb529f78a543deaf778dfaffcb012aef3c11.rev
./web-nodejs-sample/.git/objects/pack/pack-00c9cb529f78a543deaf778dfaffcb012aef3c11.idx
./web-nodejs-sample/.git/objects/info/
./web-nodejs-sample/.git/HEAD
./web-nodejs-sample/.git/refs/
./web-nodejs-sample/.git/refs/heads/
./web-nodejs-sample/.git/refs/heads/main
./web-nodejs-sample/.git/refs/tags/
./web-nodejs-sample/.git/refs/remotes/
./web-nodejs-sample/.git/refs/remotes/origin/
./web-nodejs-sample/.git/refs/remotes/origin/HEAD
./web-nodejs-sample/.git/packed-refs
./web-nodejs-sample/.git/logs/
./web-nodejs-sample/.git/logs/refs/
./web-nodejs-sample/.git/logs/refs/remotes/
./web-nodejs-sample/.git/logs/refs/remotes/origin/
./web-nodejs-sample/.git/logs/refs/remotes/origin/HEAD
./web-nodejs-sample/.git/logs/refs/heads/
./web-nodejs-sample/.git/logs/refs/heads/main
./web-nodejs-sample/.git/logs/HEAD
./web-nodejs-sample/.git/index
./web-nodejs-sample/.git/FETCH_HEAD
./web-nodejs-sample/.gitattributes
./web-nodejs-sample/.github/
./web-nodejs-sample/.github/CODEOWNERS
./web-nodejs-sample/.gitignore
./web-nodejs-sample/.vscode/
./web-nodejs-sample/.vscode/launch.json
./web-nodejs-sample/LICENSE
./web-nodejs-sample/README.md
./web-nodejs-sample/app/
./web-nodejs-sample/app/app.js
./web-nodejs-sample/devfile.yaml
./web-nodejs-sample/package-lock.json
./web-nodejs-sample/package.json
./.code-workspace
Restore completed successfully.

@dkwon17
Copy link
Collaborator

dkwon17 commented Jan 27, 2026

I am running into an issue in this particular scenario, if I have the DWOC with an auth secret to a private repo like so:

apiVersion: controller.devfile.io/v1alpha1
config:
  workspace:
    backupCronJob:
      enable: true
      oras:
        extraArgs: '--insecure'
      registry:
        authSecret: quay-credentials
        path: quay.io/dkwon17/private
      schedule: '*/2 * * * *'
kind: DevWorkspaceOperatorConfig
metadata:
  name: devworkspace-operator-config
  namespace: openshift-operators

and if I manually create the auth secret named quay-credentials in the workspace's namespace, and then create a workspace with:

spec:
  template:
    attributes:
      controller.devfile.io/restore-source-image: 'quay.io/dkwon17/private/admin-devspaces/quarkus-api-example-ghtp:latest'
      controller.devfile.io/restore-workspace: 'true'

the workspace pods create and terminated infinitely due to the deployment being updated repeatedly:

Screen.Recording.2026-01-27.at.6.14.20.PM.mov

@akurinnoy @rohanKanojia have you experienced something similar?

I need to investigate the cause/solution a bit more, but the problem occurs because for whatever reason, this situation causes volume mounts' ordering to change repeatedly:
image

@dkwon17 dkwon17 closed this Jan 27, 2026
@dkwon17
Copy link
Collaborator

dkwon17 commented Jan 27, 2026

Oops, I'm sorry for the accidental close

@dkwon17 dkwon17 reopened this Jan 27, 2026
MountPath: constants.DefaultProjectsSourcesRoot,
},
}
registryAuthSecret, err := secrets.HandleRegistryAuthSecret(ctx, k8sClient, workspace.DevWorkspace, workspace.Config, "", scheme, log)
Copy link
Collaborator

@dkwon17 dkwon17 Jan 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we refactor HandleRegistryAuthSecret to avoid having the caller pass in "" as a parameter in:

HandleRegistryAuthSecret(ctx, k8sClient, workspace.DevWorkspace, workspace.Config, "", scheme, log)

?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you suggest? null value or a different solution?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I notice for the restore init container, we are using HandleRegistryAuthSecret to only get the secret, and not copy. But in the backup cron job, we use it for both get and copy:

registryAuthSecret, err := secrets.HandleRegistryAuthSecret(ctx, r.Client, workspace, dwOperatorConfig.Config, dwOperatorConfig.Namespace, r.Scheme, log)

I was thinking about creating:

func GetNamespaceRegistryAuthSecret(ctx context.Context, c client.Client, workspace *dw.DevWorkspace,
	dwOperatorConfig *controllerv1alpha1.OperatorConfiguration, operatorConfigNamespace string, scheme *runtime.Scheme, log logr.Logger,
) (*corev1.Secret, error) {
	return HandleRegistryAuthSecret(ctx, c, workspace, dwOperatorConfig, "", scheme, log)
}

inside pkg/secrets/backup.go, and use it here:

Suggested change
registryAuthSecret, err := secrets.HandleRegistryAuthSecret(ctx, k8sClient, workspace.DevWorkspace, workspace.Config, "", scheme, log)
registryAuthSecret, err := secrets.GetNamespaceRegistryAuthSecret(ctx, k8sClient, workspace.DevWorkspace, workspace.Config, scheme, log)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I changed the functions based on the suggestion.

A new sample image is created in the CI and is used in the integration
tests.

Signed-off-by: Ales Raszka <araszka@redhat.com>
Signed-off-by: Ales Raszka <araszka@redhat.com>
@dkwon17
Copy link
Collaborator

dkwon17 commented Jan 28, 2026

I think I found the cause of #1572 (comment). It seems unrelated to this PR. I will need to gather more evidence, and create a fix

Name: devfileConstants.ProjectsRootEnvVar,
Value: constants.DefaultProjectsSourcesRoot,
})
if workspace.Config.Workspace.BackupCronJob.OrasConfig != nil {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To me it seems like a potential nil pointer issue, when workspace restore is enabled but backup configuration is not set in DWOC.

Suggested change
if workspace.Config.Workspace.BackupCronJob.OrasConfig != nil {
if workspace.Config.Workspace.BackupCronJob != nil &&
workspace.Config.Workspace.BackupCronJob.OrasConfig != nil {

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

Comment on lines 82 to 102
err = c.Delete(ctx, existingNamespaceSecret)
if err != nil {
return nil, err
}
}
namespaceSecret = &corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: constants.DevWorkspaceBackupAuthSecretName,
Namespace: workspace.Namespace,
Labels: map[string]string{
constants.DevWorkspaceIDLabel: workspace.Status.DevWorkspaceId,
constants.DevWorkspaceWatchSecretLabel: "true",
},
},
Data: sourceSecret.Data,
Type: sourceSecret.Type,
}
if err := controllerutil.SetControllerReference(workspace, namespaceSecret, scheme); err != nil {
return nil, err
}
err = c.Create(ctx, namespaceSecret)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When multiple workspaces start simultaneously they race to copy the same secret causing failures.

	err = c.Delete(ctx, existingNamespaceSecret) // race window opens
// time gap
err = c.Create(ctx, namespaceSecret) // race window closes

I think you can update instead of delete and create. Does this make sense?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I replaced the function with the SyncObjectWithCluster that performs object sync in a standardized way and only syncs it when secrets is changed.

MountPath: constants.DefaultProjectsSourcesRoot,
},
}
registryAuthSecret, err := secrets.HandleRegistryAuthSecret(ctx, k8sClient, workspace.DevWorkspace, workspace.Config, "", scheme, log)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you please clarify why you passed an empty string for operatorNamespace?
I noticed that the backup implementation retrieves the operator namespace and passes it to the same function.
Sorry if this has already been discussed. If so, please point that out to me.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@akurinnoy I created a similar discussion here: #1572 (comment)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I addressed this based on the suggestion.

Allda added 5 commits January 30, 2026 10:05
Signed-off-by: Ales Raszka <araszka@redhat.com>
Signed-off-by: Ales Raszka <araszka@redhat.com>
In case the backup config is not present the value might be null and
fails. The new condition handles it.

Signed-off-by: Ales Raszka <araszka@redhat.com>
The delay between checking the empty dir and copying a backup content
might cause an issue. This fix moves the check right before the content
is being copied which minimize the delay.

Signed-off-by: Ales Raszka <araszka@redhat.com>
The previous solution always deleted a secret if exist and re-create it.
This can lead to potential issues.
The new code uses SyncObjectWithCluster that is used across a whole
codebase and minimize the risk of issues.

Signed-off-by: Ales Raszka <araszka@redhat.com>
@Allda Allda force-pushed the 23570-restore-workspace branch from 50d4dd0 to 27ee785 Compare January 30, 2026 09:06
@Allda
Copy link
Collaborator Author

Allda commented Feb 2, 2026

@dkwon17 I addressed all the code review comments. Is this PR good to be merged?

@rohanKanojia
Copy link
Member

rohanKanojia commented Feb 2, 2026

@Allda : Could you rebase your branch against main (to also bring in 0607887) ? I want to test restore for per-workspace scenarios.

Comment on lines +107 to +110
//Role kinds
Role = "Role"
// ClusterRole kind
ClusterRole = "ClusterRole"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems to be a very generic name and can be mistaken for an API concept or exported constant from Kubernetes (which doesn’t exist).

I suggest renaming it to something like rbacRoleKind / rbacClusterRoleKind, or documenting that this is a literal Kind string used for comparison.

Suggested change
//Role kinds
Role = "Role"
// ClusterRole kind
ClusterRole = "ClusterRole"
// Role kind
rbacRoleKind = "Role"
// ClusterRole kind
rbacClusterRoleKind = "ClusterRole"

func HandleRegistryAuthSecret(ctx context.Context, c client.Client, workspace *dw.DevWorkspace,
dwOperatorConfig *controllerv1alpha1.OperatorConfiguration, operatorConfigNamespace string, scheme *runtime.Scheme, log logr.Logger,
) (*corev1.Secret, error) {
secretName := dwOperatorConfig.Workspace.BackupCronJob.Registry.AuthSecret
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Potential nil pointer deference:

Suggested change
secretName := dwOperatorConfig.Workspace.BackupCronJob.Registry.AuthSecret
if dwOperatorConfig.Workspace == nil ||
dwOperartorConfig.Workspace.BackupCronJob == nil ||
dwOperatorConfig.Workspace.BackupCronJob.Registry == nil {
return nil, fmt.Errorf("backup/restore configuration not properly set in DevWorkspaceOperatorConfig")
}
secretName := dwOperatorConfig.Workspace.BackupCronJob.Registry.AuthSecret

Comment on lines +83 to +95
// Construct the desired secret state
desiredSecret := &corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: constants.DevWorkspaceBackupAuthSecretName,
Namespace: workspace.Namespace,
Labels: map[string]string{
constants.DevWorkspaceIDLabel: workspace.Status.DevWorkspaceId,
constants.DevWorkspaceWatchSecretLabel: "true",
},
},
Data: sourceSecret.Data,
Type: sourceSecret.Type,
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here seems to be another race condition in secret copying. If multiple workspaces are restoring simultaneously in the same namespace, they will race to create/update the same secret name. Does this make sense?

Suggested change
// Construct the desired secret state
desiredSecret := &corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: constants.DevWorkspaceBackupAuthSecretName,
Namespace: workspace.Namespace,
Labels: map[string]string{
constants.DevWorkspaceIDLabel: workspace.Status.DevWorkspaceId,
constants.DevWorkspaceWatchSecretLabel: "true",
},
},
Data: sourceSecret.Data,
Type: sourceSecret.Type,
}
// Construct the desired secret state
desiredSecret := &corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: constants.DevWorkspaceBackupAuthSecretName + "=" + workspace.Status.DevWorkspaceId,
Namespace: workspace.Namespace,
Labels: map[string]string{
constants.DevWorkspaceIDLabel: workspace.Status.DevWorkspaceId,
constants.DevWorkspaceWatchSecretLabel: "true",
},
},
Data: sourceSecret.Data,
Type: sourceSecret.Type,
}

@rohanKanojia
Copy link
Member

Now that I'm testing with updated changes, I'm seeing issue that after creating restored workspace manifest . Restore pod correctly starts workspace-restore container and it restores devworkspace correctly too.

However, the DevWorkspace is not able to come out of Starting phase:

oc get dw
NAMESPACE             NAME                                  DEVWORKSPACE ID             PHASE      INFO
openshift-operators   test-devworkspace-should-get-backup   workspacedd4c47ceaf59422a   Starting   Waiting for workspace deployment

oc get pods
NAME                                               READY   STATUS    RESTARTS      AGE
devworkspace-controller-manager-5f5db7d5bd-xnwn6   1/1     Running   0             52m
devworkspace-webhook-server-5fbcc75dd-lv5b6        1/1     Running   0             52m
devworkspace-webhook-server-5fbcc75dd-vsmdb        1/1     Running   1 (52m ago)   52m
workspacedd4c47ceaf59422a-778f75dc67-7wxvf         1/1     Running   0             4m16s

oc logs pod/workspacedd4c47ceaf59422a-778f75dc67-7wxvf -cworkspace-restore                                              ─╯

Restoring devworkspace from image 'quay.io/rokumar/openshift-operators/test-devworkspace-should-get-backup:latest' to path '/projects'
Downloading 2d633520a986 devworkspace-backup.tar.gz
Downloaded  2d633520a986 devworkspace-backup.tar.gz
Pulled [registry] quay.io/rokumar/openshift-operators/test-devworkspace-should-get-backup:latest
Digest: sha256:5471f6cf07e78565f2ecc5624ff81fba1ce65953864434b67614cdc4f818581a
./
./web-nodejs-sample/
./web-nodejs-sample/.git/
./web-nodejs-sample/.git/branches/
./web-nodejs-sample/.git/description
./web-nodejs-sample/.git/hooks/
./web-nodejs-sample/.git/hooks/applypatch-msg.sample
./web-nodejs-sample/.git/hooks/commit-msg.sample
./web-nodejs-sample/.git/hooks/fsmonitor-watchman.sample
./web-nodejs-sample/.git/hooks/post-update.sample
./web-nodejs-sample/.git/hooks/pre-applypatch.sample
./web-nodejs-sample/.git/hooks/pre-commit.sample
./web-nodejs-sample/.git/hooks/pre-merge-commit.sample
./web-nodejs-sample/.git/hooks/pre-push.sample
./web-nodejs-sample/.git/hooks/pre-rebase.sample
./web-nodejs-sample/.git/hooks/pre-receive.sample
./web-nodejs-sample/.git/hooks/prepare-commit-msg.sample
./web-nodejs-sample/.git/hooks/push-to-checkout.sample
./web-nodejs-sample/.git/hooks/sendemail-validate.sample
./web-nodejs-sample/.git/hooks/update.sample
./web-nodejs-sample/.git/info/
./web-nodejs-sample/.git/info/exclude
./web-nodejs-sample/.git/config
./web-nodejs-sample/.git/objects/
./web-nodejs-sample/.git/objects/pack/
./web-nodejs-sample/.git/objects/pack/pack-00c9cb529f78a543deaf778dfaffcb012aef3c11.pack
./web-nodejs-sample/.git/objects/pack/pack-00c9cb529f78a543deaf778dfaffcb012aef3c11.rev
./web-nodejs-sample/.git/objects/pack/pack-00c9cb529f78a543deaf778dfaffcb012aef3c11.idx
./web-nodejs-sample/.git/objects/info/
./web-nodejs-sample/.git/HEAD
./web-nodejs-sample/.git/refs/
./web-nodejs-sample/.git/refs/heads/
./web-nodejs-sample/.git/refs/heads/main
./web-nodejs-sample/.git/refs/tags/
./web-nodejs-sample/.git/refs/remotes/
./web-nodejs-sample/.git/refs/remotes/origin/
./web-nodejs-sample/.git/refs/remotes/origin/HEAD
./web-nodejs-sample/.git/packed-refs
./web-nodejs-sample/.git/logs/
./web-nodejs-sample/.git/logs/refs/
./web-nodejs-sample/.git/logs/refs/remotes/
./web-nodejs-sample/.git/logs/refs/remotes/origin/
./web-nodejs-sample/.git/logs/refs/remotes/origin/HEAD
./web-nodejs-sample/.git/logs/refs/heads/
./web-nodejs-sample/.git/logs/refs/heads/main
./web-nodejs-sample/.git/logs/HEAD
./web-nodejs-sample/.git/index
./web-nodejs-sample/.git/FETCH_HEAD
./web-nodejs-sample/.gitattributes
./web-nodejs-sample/.github/
./web-nodejs-sample/.github/CODEOWNERS
./web-nodejs-sample/.gitignore
./web-nodejs-sample/.vscode/
./web-nodejs-sample/.vscode/launch.json
./web-nodejs-sample/LICENSE
./web-nodejs-sample/README.md
./web-nodejs-sample/app/
./web-nodejs-sample/app/app.js
./web-nodejs-sample/devfile.yaml
./web-nodejs-sample/package-lock.json
./web-nodejs-sample/package.json
./.code-workspace
Restore completed successfully.
╭─      ~/go/src/github.com/devfile/devworkspace-operator   pullRequest1572 ≢  ?3  36                                                                                                1.24.6     19:54:35  ─╮
╰─ oc exec -it pod/workspacedd4c47ceaf59422a-778f75dc67-7wxvf -- /bin/bash                                                 ─╯
Defaulted container "dev" out of: dev, workspace-restore (init), che-code-injector (init)
projects $ ls
web-nodejs-sample
projects $ cd web-nodejs-sample/
web-nodejs-sample (main) $ ls
LICENSE  README.md  app  devfile.yaml  package-lock.json  package.json
web-nodejs-sample (main) $ cat README.md 
# web-nodejs-sample

ExpressJS Sample Application

# Developer Workspace
[![Contribute](http://beta.codenvy.com/factory/resources/codenvy-contribute.svg)](http://beta.codenvy.com/f?id=r8et9w6vohmqvro8)

# Stack to use

FROM [codenvy/node](https://hub.docker.com/r/codenvy/node/)

# How to run

| #       | Description           | Command  |
| :------------- |:-------------| :-----|
| 1      | Run | `cd ${current.project.path}/app && node app.js` |## Modified via backup test
web-nodejs-sample (main) $ exit

}
if workspace.Config.Workspace.ProjectCloneConfig.ImagePullPolicy != "" {
projectCloneOptions.PullPolicy = config.Workspace.ProjectCloneConfig.ImagePullPolicy
if restore.IsWorkspaceRestoreRequested(&workspace.Spec.Template) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see every reconcile checks IsWorkspaceRestoreRequested(), I think this would keep adding restore init container, and the workspace would never reach Running phase.

The restore attribute should be automatically removed after successful completion.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants